﻿using System;
using IPCChannel;
using UProveCrypto;

namespace UProveAPI
{
    public class Verifier
    {
        private IssuerParameters issuerParams;
        private IIPCClient ipcClient;

        public Verifier(IIPCClient ipcClient)
        {
            this.ipcClient = ipcClient;
            ipcClient.MessageReceived += IpcClientOnMessageReceived;
        }

        public void Start()
        {
            ipcClient.StartListening();
        }

        private void IpcClientOnMessageReceived(IPCMessage message)
        {
            switch (message.MessageType)
            {
                case IPCMessageTypes.SetupMessage:
                    SetupMessage setupMsg = message as SetupMessage;
                    HandleSetupMessage(setupMsg);
                    break;
                case IPCMessageTypes.PresentationMessage:
                    PresentationMessage presentationMsg = message as PresentationMessage;
                    HandlePresentationMessage(presentationMsg);
                    break;
                default:
                    break;
            }
        }

        private void HandleSetupMessage(SetupMessage setupMessage)
        {
            switch (setupMessage.DataType)
            {
                case SetupDataType.VerifyParameters:
                    Console.WriteLine("Received Issuer Parameters");
                    issuerParams = new IssuerParameters(setupMessage.IssuerParamsJSON);
                    issuerParams.Verify();
                    Console.WriteLine("Issuer is verified!\n");
                    break;
                default:
                    break;
            }
        }

        private void HandlePresentationMessage(PresentationMessage presentationMessage)
        {
            switch (presentationMessage.DataType)
            {
                case PresentationDataType.PresentToken:
                    PresentationMessage resMsg = new PresentationMessage(PresentationDataType.TokenVerification);

                    resMsg.Verified = PresentUProveToken(presentationMessage.SerializedToken, presentationMessage.PresentationProof,
                                                         presentationMessage.DisclosedIndices, presentationMessage.Committed,
                                                         presentationMessage.Message, presentationMessage.Scope);

                    ipcClient.Send(presentationMessage.SenderIp, presentationMessage.SenderPort, resMsg);

                    Console.WriteLine("Sent verification message to Prover\n");
                    break;
                default:
                    break;
            }
        }

        public bool PresentUProveToken(string tokenStr, string proof, int[] disclosed, int[] committed, byte[] message, byte[] scope)
        {
            // Verify the presentation proof
            UProveToken token = issuerParams.Deserialize<UProveToken>(tokenStr);
            VerifierPresentationProtocolParameters vppp = new VerifierPresentationProtocolParameters(issuerParams, disclosed, message, token);
            vppp.Committed = committed;

            // If a scope is defined, we use the first attribute to derive a scope exclusive pseudonym            
            vppp.PseudonymAttributeIndex = (scope == null ? 0 : 1);
            vppp.PseudonymScope = scope;
            vppp.DeviceMessage = null;

            try
            {
                issuerParams.Deserialize<PresentationProof>(proof).Verify(vppp);
            }
            catch (InvalidUProveArtifactException ex)
            {
                Console.WriteLine("Presentation proof is invalid! Go Away! :(");
                Console.WriteLine(ex.Message + Environment.NewLine);
                return false;
            }
            
            Console.WriteLine("Presentation Proof is valid! Have all my goodies! :)");

            return true;
        }
    }
}
